package edu.hitsz.application;

import edu.hitsz.StartGame;
import edu.hitsz.aircraft.*;
import edu.hitsz.aircraftfactory.BossFactory;
import edu.hitsz.aircraftfactory.EliteFactory;
import edu.hitsz.aircraftfactory.MobFactory;
import edu.hitsz.bullet.AbstractBullet;
import edu.hitsz.basic.AbstractFlyingObject;
import edu.hitsz.aircraft.AbstractEnemy;
import edu.hitsz.prop.AbstractProp;
import edu.hitsz.prop.BombProp;
import edu.hitsz.scorelist.ScoreDao;
import edu.hitsz.scorelist.ScoreDaoImpl;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;

/**
 * 游戏主面板，游戏启动
 *
 * @author hitsz
 */
public abstract class Game extends JPanel {

    protected int backGroundTop = 0;

    /**
     * Scheduled 线程池，用于任务调度
     */
    private final ScheduledExecutorService executorService;

    /**
     * 时间间隔(ms)，控制刷新频率
     */
    private int timeInterval = 40;

    protected final HeroAircraft heroAircraft;
    protected AbstractEnemy bossAircraft;
    protected final List<AbstractEnemy> enemyAircrafts;
    protected final List<AbstractBullet> heroBullets;
    protected final List<AbstractBullet> enemyBullets;
    protected final List<AbstractProp> props;
    protected final List<Explode> explodeObj;

    protected int enemyMaxNumber;

    /**
     * 道具掉落的概率
     */
    protected double probability;

    /**
     * 精英敌机产生的概率
     */
    protected double eliteProbability;

    private boolean gameOverFlag = false;
    public static int score = 0;
    protected int time = 0;
    /**
     * 周期（ms)
     * 指示敌机的产生频率
     */
    protected int enemyDuration;
    private int enemyCycleTime = 0;
    /**
     * 周期（ms)
     * 指示敌机子弹的发射频率
     */
    protected int enemyBulletDuration;
    private int enemyBulletCycleTime = 0;
    /**
     * 周期（ms)
     * 指示英雄机子弹的发射频率
     */
    private int heroBulletDuration = 300;
    private int heroBulletCycleTime = 0;

    /**
     * Boss机产生的阈值
     */
    protected int bossScoreThreshold;

    /**
     * 是否产生Boss敌机
     */
    protected boolean createBoss;

    /**
     * 难度增加的间隔时间
     */
    protected int createdifficulty;

    /**
     * 敌机属性提升倍率
     */
    public static double magnification = 1;

    /**
     * 每次召唤Boss机的血量
     */
    public static int BossHp = 1000;

    /**
     * 背景音乐
     */
    public static MusicThread bgm;
    public static MusicThread bgmBoss;

    /**
     * 背景图片
     */
    protected static BufferedImage BACKGROUND_IMAGE;

    public Game() {
        heroAircraft = HeroAircraft.creatHeroAircraft();
        bossAircraft = null;
        enemyAircrafts = new LinkedList<>();
        heroBullets = new LinkedList<>();
        enemyBullets = new LinkedList<>();
        props = new LinkedList<>();
        explodeObj = new LinkedList<>();

        /**
         * Scheduled 线程池，用于定时任务调度
         * 关于alibaba code guide：可命名的 ThreadFactory 一般需要第三方包
         * apache 第三方库： org.apache.commons.lang3.concurrent.BasicThreadFactory
         */
        this.executorService = new ScheduledThreadPoolExecutor(1,
                new BasicThreadFactory.Builder().namingPattern("game-action-%d").daemon(true).build());

        //启动英雄机鼠标监听
        new HeroController(this, heroAircraft);
    }

    /**
     * 游戏启动入口，执行游戏逻辑
     */
    public void action() {

        //启动背景音乐线程
        if(StartGame.isPlay){
            bgm = new MusicThread(MusicThread.bgm);
            bgm.setLoop(true);
            bgm.start();
            if (createBoss) {
                bgmBoss = new MusicThread(MusicThread.bgmBoss);
                bgmBoss.setLoop(true);
                bgmBoss.setPlay(false);
                bgmBoss.start();
            }
        }

        // 定时任务：绘制、对象产生、碰撞判定、击毁及结束判定
        Runnable task = () -> {

            time += timeInterval;

            // 周期性执行（控制频率）
            if (enemyTimeCountAndNewCycleJudge()) {
                System.out.println(time);
                // 新敌机产生
                if (enemyAircrafts.size() < enemyMaxNumber) {
                    if(Math.random() <= eliteProbability){
                        enemyAircrafts.add(new EliteFactory().createAircraft());
                    }
                    else{
                        enemyAircrafts.add(new MobFactory().createAircraft());
                    }
                }
            }

            //当得分每超过一次阈值bossScoreThreshold时，产生一次Boss机（同一时刻只有一架）
            if (bossAircraft == null && (score % bossScoreThreshold == 0) && (score != 0) && createBoss){
                createBoss();
            }

            if (enemyBulletDurationTimeCountAndNewCycleJudge()) {
                // 敌机射出子弹
                enemyShootAction();
            }

            if (heroBulletDurationTimeCountAndNewCycleJudge()) {
                // 英雄机射出子弹
                heroShootAction();
            }

            // 子弹移动
            bulletsMoveAction();

            // 飞机移动
            aircraftsMoveAction();

            //道具移动
            propsMoveAction();

            // 撞击检测
            try {
                crashCheckAction();
            } catch (InterruptedException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
                e.printStackTrace();
            }

            // 后处理
            postProcessAction();

            //每个时刻重绘界面
            repaint();

            //提高难度
            increaseddifficulty();

            // 游戏结束检查
            if (heroAircraft.getHp() <= 0) {
//                //添加英雄机爆炸效果
//                explodeObj.add(new Explode(heroAircraft.getLocationX(),heroAircraft.getLocationY()));
//                explodeObj.get(explodeObj.size() - 1).paint(g);
                // 游戏结束
                if(StartGame.isPlay) {
                    bgm.setPlay(false);
                    if (createBoss) {
                        bgmBoss.setPlay(false);
                    }
                    new MusicThread(MusicThread.gameOver).start();
                }
                executorService.shutdown();
                gameOverFlag = true;
                System.out.println("Game Over!");
                synchronized (Main.object){
                    Main.object.notify();
                }
            }
        };

        /**
         * 以固定延迟时间进行执行
         * 本次任务执行完成后，需要延迟设定的延迟时间，才会执行新的任务
         */
        executorService.scheduleWithFixedDelay(task, timeInterval, timeInterval, TimeUnit.MILLISECONDS);
    }

    //***********************
    //      Action 各部分
    //***********************

    public void createBoss() {
        if(StartGame.isPlay) {
            bgm.setPlay(false);
            bgmBoss.setPlay(true);
        }
        bossAircraft = new BossFactory().createAircraft();
    }

    private boolean enemyTimeCountAndNewCycleJudge() {
        enemyCycleTime += timeInterval;
        if (enemyCycleTime >= enemyDuration && enemyCycleTime - timeInterval < enemyCycleTime) {
            // 跨越到新的周期
            enemyCycleTime %= enemyDuration;
            return true;
        } else {
            return false;
        }
    }

    private boolean enemyBulletDurationTimeCountAndNewCycleJudge() {
        enemyBulletCycleTime += timeInterval;
        if (enemyBulletCycleTime >= enemyBulletDuration && enemyBulletCycleTime - timeInterval < enemyBulletCycleTime) {
            // 跨越到新的周期
            enemyBulletCycleTime %= enemyBulletDuration;
            return true;
        } else {
            return false;
        }
    }

    private boolean heroBulletDurationTimeCountAndNewCycleJudge() {
        heroBulletCycleTime += timeInterval;
        if (heroBulletCycleTime >= heroBulletDuration && heroBulletCycleTime - timeInterval < heroBulletCycleTime) {
            // 跨越到新的周期
            heroBulletCycleTime %= heroBulletDuration;
            return true;
        } else {
            return false;
        }
    }

    private void enemyShootAction() {
        // TODO 敌机射击
        for(AbstractEnemy enemyaircraft : enemyAircrafts){
            enemyBullets.addAll(enemyaircraft.shoot());
        }
        if (bossAircraft != null) {
            enemyBullets.addAll(bossAircraft.shoot());
        }
    }

    private void heroShootAction() {
        // 英雄机射击
        heroBullets.addAll(heroAircraft.shoot());
    }

    private void bulletsMoveAction() {
        for (AbstractBullet bullet : heroBullets) {
            bullet.forward();
        }
        for (AbstractBullet bullet : enemyBullets) {
            bullet.forward();
        }
    }

    private void propsMoveAction() {
        for (AbstractProp prop : props) {
            prop.forward();
        }
    }

    private void aircraftsMoveAction() {
        for (AbstractEnemy enemyAircraft : enemyAircrafts) {
            enemyAircraft.forward();
        }
        if (bossAircraft != null) {
            bossAircraft.forward();
        }
    }


    /**
     * 碰撞检测：
     * 1. 敌机攻击英雄
     * 2. 英雄攻击/撞击敌机
     * 3. 英雄获得补给
     */
    private void crashCheckAction() throws InterruptedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // TODO 敌机子弹攻击英雄
        for(AbstractBullet bullet : enemyBullets){
            if (bullet.notValid()) {
                continue;
            }
            if (heroAircraft.crash(bullet)) {
                // 英雄机撞击到敌机子弹
                // 英雄机损失一定生命值
                heroAircraft.decreaseHp(bullet.getPower());
                if(StartGame.isPlay) {
                    new MusicThread(MusicThread.bulletHit).start();
                }
                bullet.vanish();
            }
        }
        // 英雄子弹攻击敌机
        for (AbstractBullet bullet : heroBullets) {
            if (bullet.notValid()) {
                continue;
            }
            if (bossAircraft != null && !bossAircraft.notValid() && bossAircraft.crash(bullet) && createBoss) {
                if(StartGame.isPlay) {
                    new MusicThread(MusicThread.bulletHit).start();
                }
                    bossAircraft.decreaseHp(bullet.getPower());
                    bullet.vanish();
                    if (bossAircraft.notValid()) {
                        score += 20;
                        if(StartGame.isPlay) {
                            new MusicThread(MusicThread.bombExplosion).start();
                            bgmBoss.setPlay(false);
                            bgm.setPlay(true);
                        }
                        explodeObj.add(new Explode(bossAircraft.getLocationX()-35,bossAircraft.getLocationY()-50));
                        if(Math.random() <= probability) {
                            props.add(bossAircraft.drop());
                        }
                    }
                    continue;
            }
            for (AbstractEnemy enemyAircraft : enemyAircrafts) {
                if (enemyAircraft.notValid()) {
                    // 已被其他子弹击毁的敌机，不再检测
                    // 避免多个子弹重复击毁同一敌机的判定
                    continue;
                }
                if (enemyAircraft.crash(bullet)) {
                    // 敌机撞击到英雄机子弹
                    // 敌机损失一定生命值
                    enemyAircraft.decreaseHp(bullet.getPower());
                    if(StartGame.isPlay) {
                        new MusicThread(MusicThread.bulletHit).start();
                    }
                    bullet.vanish();
                    if (enemyAircraft.notValid()) {
                        // TODO 获得分数，产生道具补给
                        score += 10;
                        if(StartGame.isPlay) {
                            new MusicThread(MusicThread.bombExplosion).start();
                        }
                        explodeObj.add(new Explode(enemyAircraft.getLocationX()-35,enemyAircraft.getLocationY()-50));
                        if(enemyAircraft.getClass().getName() == "edu.hitsz.aircraft.EliteEnemy" && Math.random() <= probability){
                                props.add(enemyAircraft.drop());
                        }
                    }
                }
                // 英雄机 与 敌机 相撞，均损毁
                if (enemyAircraft.crash(heroAircraft) || heroAircraft.crash(enemyAircraft)) {
                    enemyAircraft.vanish();
                    heroAircraft.decreaseHp(Integer.MAX_VALUE);
                    if(StartGame.isPlay) {
                        new MusicThread(MusicThread.bombExplosion).start();
                    }
                }
                // 英雄机 与 boss机 相撞，均损毁
                if (bossAircraft != null && (bossAircraft.crash(heroAircraft) || heroAircraft.crash(bossAircraft))) {
                    enemyAircraft.vanish();
                    heroAircraft.decreaseHp(Integer.MAX_VALUE);
                    if(StartGame.isPlay) {
                        new MusicThread(MusicThread.bombExplosion).start();
                    }
                }
            }
        }

        // Todo: 我方获得道具，道具生效
        for(AbstractProp prop : props){
            if (heroAircraft.crash(prop)){
                prop.vanish();
                if(StartGame.isPlay) {
                    new MusicThread(MusicThread.getSupply).start();
                }
                if ("edu.hitsz.prop.BombProp".equals(prop.getClass().getName())) {
                    BombProp.class.getMethod("addSubscriber",List.class,List.class).invoke(prop,enemyAircrafts,enemyBullets);
                    prop.effect(heroAircraft,explodeObj);
                } else {
                    prop.effect(heroAircraft,explodeObj);
                }
            }
        }
    }

    /**
     * 后处理：
     * 1. 删除无效的子弹
     * 2. 删除无效的敌机
     * 3. 检查英雄机生存
     * <p>
     * 无效的原因可能是撞击或者飞出边界
     */
    private void postProcessAction() {
        enemyBullets.removeIf(AbstractFlyingObject::notValid);
        heroBullets.removeIf(AbstractFlyingObject::notValid);
        enemyAircrafts.removeIf(AbstractFlyingObject::notValid);
        props.removeIf(AbstractFlyingObject::notValid);
        explodeObj.removeIf(AbstractFlyingObject::notValid);
        if (bossAircraft != null && bossAircraft.notValid()) {
            bossAircraft = null;
        }
    }

    /**
     * 提高难度
     */
    public abstract void increaseddifficulty();

    //***********************
    //      Paint 各部分
    //***********************

    /**
     * 重写paint方法
     * 通过重复调用paint方法，实现游戏动画
     *
     * @param  g
     */
    @Override
    public void paint(Graphics g) {
        super.paint(g);

        // 绘制背景,图片滚动
        g.drawImage(BACKGROUND_IMAGE, 0, this.backGroundTop - Main.WINDOW_HEIGHT, null);
        g.drawImage(BACKGROUND_IMAGE, 0, this.backGroundTop, null);
        this.backGroundTop += 1;
        if (this.backGroundTop == Main.WINDOW_HEIGHT) {
            this.backGroundTop = 0;
        }

        // 先绘制子弹，后绘制飞机
        // 这样子弹显示在飞机的下层
        paintImageWithPositionRevised(g, enemyBullets);
        paintImageWithPositionRevised(g, heroBullets);

        paintImageWithPositionRevised(g, enemyAircrafts);

        g.drawImage(ImageManager.HERO_IMAGE, heroAircraft.getLocationX() - ImageManager.HERO_IMAGE.getWidth() / 2,
                heroAircraft.getLocationY() - ImageManager.HERO_IMAGE.getHeight() / 2, null);

        if (bossAircraft != null) {
            g.drawImage(ImageManager.BOSS_ENEMY_IMAGE, bossAircraft.getLocationX() - ImageManager.BOSS_ENEMY_IMAGE.getWidth() / 2,
                    bossAircraft.getLocationY() - ImageManager.BOSS_ENEMY_IMAGE.getHeight() / 2, null);
        }

        //绘制爆炸效果
        for(Explode explodeobj : explodeObj) {
            explodeobj.paint(g);
            if (explodeobj.getExplodeCount() == 15){
                explodeobj.vanish();
            }
        }
        //绘制道具
        paintImageWithPositionRevised(g,props);
        //绘制得分和生命值
        paintScoreAndLife(g);

    }

    public void paintImageWithPositionRevised(Graphics g, List<? extends AbstractFlyingObject> objects) {
        if (objects.size() == 0) {
            return;
        }

        for (AbstractFlyingObject object : objects) {
            BufferedImage image = object.getImage();
            assert image != null : objects.getClass().getName() + " has no image! ";
            g.drawImage(image, object.getLocationX() - image.getWidth() / 2,
                    object.getLocationY() - image.getHeight() / 2, null);
        }
    }

    public void paintScoreAndLife(Graphics g) {
        int x = 10;
        int y = 25;
        g.setColor(new Color(16711680));
        g.setFont(new Font("SansSerif", Font.BOLD, 22));
        g.drawString("SCORE:" + this.score, x, y);
        y = y + 20;
        g.drawString("LIFE:" + this.heroAircraft.getHp(), x, y);
    }


}
